﻿///////////////////////////////////////////////////////////////////////////////
// File:        Acceptor.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include <cassert>
#include <memory>

#include "nio/net/Acceptor.hpp"
using namespace nio::net;

Acceptor::Acceptor()
    : state_(READY)
    , sock_()
    , cnfLinger_(true)
    , connAcceptFN_()
    , closeFN_()
{

}

Acceptor::~Acceptor()
{

}

bool Acceptor::open(std::string addr, int port, int backlog)
{
    assert(state_ == READY);

    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));

    saddr.sin_family = AF_INET;
#if defined(__WINDOWS__)
    saddr.sin_addr.S_un.S_addr = ::inet_addr(addr.c_str());
#elif defined(__LINUX__)
    saddr.sin_addr.s_addr = ::inet_addr(addr.c_str());
#endif
    saddr.sin_port = ::htons(u_short(port));


    if (!sock_.open(AF_INET, SOCK_STREAM))
        return false;

    if (!sock_.setNonblocking(true))
        return false;

    if (!sock_.bind((const struct sockaddr*)&saddr, sizeof(saddr)))
        return false;

    if (!sock_.listen(backlog))
        return false;

    setState(RUNNING);

    return true;
}

void Acceptor::handleInput()
{
    if (state_ != RUNNING)
        return;

    sock_t newSock = sock_.accept(NULL, NULL);
    if (newSock != INVALID_SOCKET)
    {
        do
        {
            if (!Socket::setNonblocking(newSock, true))
                break;
            if (!Socket::setLinger(newSock, cnfLinger_))
                break;

            connAcceptFN_(newSock);
            return;
        } while (false);

        Socket::close(newSock);
    }
}

void Acceptor::handleOutput()
{

}

void Acceptor::handleError()
{
    assert(closeFN_);

    if (state_ != RUNNING)
        return;

    setState(Acceptor::EXITING);
    closeFN_();
}

void Acceptor::handleHeartbeat()
{

}


